/*
frigOS
Licensed under GPLv3

Prototypes and definitions for using USART1
Included by default in serial.h
*/

#ifndef __USART1_H__
#define __USART1_H__

#include "serial.h"
#include "dynamixel.h"

// available USART1 frequencies
// we assume F_CPU is defined at 16MHz
// one of these should be specified when calling initUSART1(...)
typedef enum usart1_frequencies
{
    USART1_9600_BAUD = 9600,
    USART1_57600_BAUD = 57600,
    USART1_115200_BAUD = 115200
} Usart1_Frequency;
#define USART1_BAUD_RATE_9600_U2X10     207
#define USART1_BAUD_RATE_9600_U2X11     103
#define USART1_BAUD_RATE_57600_U2X10    16
#define USART1_BAUD_RATE_57600_U2X11    34
#define USART1_BAUD_RATE_115200_U2X10   8
#define USART1_BAUD_RATE_115200_U2X11   16

#ifndef USART1_DEFAULT_BAUD
#   define USART1_DEFAULT_BAUD      USART1_57600_BAUD
#endif
#ifndef USART1_DEFAULT_DOUBLE_CLOCK_FREQ
#   define USART1_DEFAULT_DOUBLE_CLOCK_FREQ     FALSE
#endif

#define USART1_RX_BUFFER_SIZE 32
#define USART1_TX_BUFFER_SIZE 32

// what is the state of the packet received from the PC?
// format is the same as the USART0 packet (standard Robotis/Dynamixel packets)
enum USART1_STATE
{
    USART1_INITIAL_STATE,       // waiting for the first byte
    USART1_HEADER1_STATE,       // received the first FF byte
    USART1_HEADER2_STATE,       // received the second FF byte
    USART1_ID_STATE,            // received the ID byte
    USART1_LENGTH_STATE,        // received the length byte
    USART1_INSTRUCTION_STATE,   // received the error code byte
    USART1_PARAMETER_STATE,     // received 1+ parameters
    USART1_CHECKSUM_STATE       // received all parameters & checksum
};

// USART1 is full-duplex, so one thread can be transmitting while the other is receiving
// make sure to lock the appropriate semaphore before sending/receiving bytes
extern volatile Semaphore usart1_tx_lock;
extern volatile Semaphore usart1_rx_lock;

// i/o queues for interrupt-driven communication
extern volatile IO_Queue rxQueue_USART1;
extern volatile IO_Queue txQueue_USART1;

// initialize USART1 with a specific baud rate
// doubleTx should normally be FALSE unless a very high baud rate is required
void initUSART1(Usart1_Frequency baud, BOOL doubleTx);

// get a byte from the Rx queue
// 0x00 is returned if the queue is empty
// check rxQueue_USART1.empty before calling this
uint8_t getByteUSART1(void);

// transmit an array to the PC
void transmitBufferUSART1(uint8_t const buffer[], uint8_t buffer_length);

// transmit a string to the PC
// the NULL terminator is NOT transmitted
void transmitStringUSART1(const char *msg);

// transmit a single byte to the PC
void transmitByteUSART1(uint8_t msg);

void transmitPacketUSART1(DXL_Packet *packet);

// transmit a single byte to the PC, bypassing the standard interrupt-driven
// communication
// this should only be used for debugging or sending bytes within an interrupt
void transmitByteUSART1_busyLoop(char msg);

// transmit a buffer to the PC, bypassing the standard interrupt-driven
// communication
// this should only be used for debugging or sending bytes within an interrupt
void transmitBufferUSART1_busyLoop(uint8_t const buffer[], uint8_t buffer_length);

// transmit a string, bypassing the standard interrupt-driven communication
// this should only be used for debugging or sending bytes within an interrupt
void transmitStringUSART1_busyLoop(const char* msg);

// transmit a buffer as ASCII hex values instead of raw binary data
void transmitASCIIBufferUSART1_busyLoop(uint8_t const buffer[], uint8_t buffer_length);

// threadable function
// listen for bytes received over USART1 and handle them
// however we need to
void monitorUSART1(void* arg);

#endif  //__USART1_H__
